﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ИИ
{
    public partial class Form1 : Form
    {
        #region данные простого

        double W1=0, W2=0, Q=0, Y=0;
        Random f = new Random();
        double e = 0;
        bool sum = false;
        double dw1 = 0, dw2 = 0, dQ = 0;

        #endregion

        #region данные многослойных

        List<double[,]> wij = new List<double[,]>();
        List<double[]> y = new List<double[]>();
        List<double[]> delta = new List<double[]>();
        double Ошибка = 1;
        bool Пауза = false;

        #endregion

        public Form1()
        {
            InitializeComponent();
        }

        #region Простой_персептрон

        void Начальные_параметры_Простой()
        {
            Table.Rows.Clear();
            string[] row0 = { "0", "0", "0" };
            string[] row1 = { "1", "0", "0" };
            string[] row2 = { "0", "1", "0" };
            string[] row3 = { "1", "1", "1" };
            Table.Rows.Add(row0);
            Table.Rows.Add(row1);
            Table.Rows.Add(row2);
            Table.Rows.Add(row3);
            Обновить_Простой();
        }
        void Обновить_Простой()
        {
            W1 = Math.Round(f.NextDouble(), 2);
            W2 = Math.Round(f.NextDouble(), 2);
            Q = Math.Round(f.NextDouble(), 2);
            w11.Text = W1.ToString();
            w22.Text = W2.ToString();
            QQ.Text = Q.ToString();
            Error.Text = e.ToString();
            w11.Refresh();
            w22.Refresh();
            QQ.Refresh();
            Table.Refresh();
            Error.Refresh();
        }
        private void button3_Click(object sender, EventArgs e)
        {
            Обновить_Простой();
        }
        double Вычисление_Простой(double X1, double X2)
        {
            double S = X1 * W1 + X2 * W2;
            return S;
        }
        bool Обучение_Простой()
        {
            bool sum1 = true;
            if (radioButton1.Checked)
            {
                for (int i = 0; i < Table.RowCount - 1; i++)
                {
                    if (Вычисление_Простой(Convert.ToDouble(Table[0, i].Value), Convert.ToDouble(Table[1, i].Value)) < Q)
                        Y = 0;
                    else Y = 1;
                    Table[3, i].Value = Y;
                    e = (Convert.ToDouble(Table[2, i].Value) - Y);
                    dw1 = e * Convert.ToDouble(Table[0, i].Value);
                    dw2 = e * Convert.ToDouble(Table[1, i].Value);
                    W1 = W1 + dw1;
                    W2 = W2 + dw2;
                    dQ = -e;
                    Q = Q + dQ;
                    if (e != 0)
                        sum1 = false;
                }
            }
            else if (radioButton2.Checked)
            {
                for (int i = 0; i < Table.RowCount - 1; i++)
                {
                    double S = Вычисление_Простой(Convert.ToDouble(Table[0, i].Value), Convert.ToDouble(Table[1, i].Value));
                    Y = 1 / (1 + Math.Exp(-S));
                    Table[3, i].Value = Y;
                    e = (Convert.ToDouble(Table[2, i].Value) - Y) * Y * (1 - Y);
                    dw1 = e * Convert.ToDouble(Table[0, i].Value);
                    dw2 = e * Convert.ToDouble(Table[1, i].Value);
                    W1 = W1 + dw1;
                    W2 = W2 + dw2;
                    if (e != 0)
                        sum1 = false;
                }
            }
            return sum1;
        }
        private void button2_Click(object sender, EventArgs e)
        {
            sum = false;
            Iteracii.Text = "0";
            while (!sum)
            {
                Iteracii.Text=(Convert.ToInt32(Iteracii.Text) + 1).ToString();
                sum = Обучение_Простой();
                Обновить_Простой();
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            YY.Text = (Convert.ToDouble(x1.Text) * Convert.ToDouble(w11.Text) + Convert.ToDouble(x2.Text) * Convert.ToDouble(w22.Text)).ToString();
        }
        private void button4_Click(object sender, EventArgs e)
        {
            sum = Обучение_Простой();
            Обновить_Простой();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            Начальные_параметры_Простой();
        }

        #endregion

        #region Трехслойный_персептрон

        private void button7_Click(object sender, EventArgs e)
        {
            Заполнение_таблицы();
            Начальные_параметры_двуслойного();
        }
        void Начальные_параметры_двуслойного()
        {
            wij.Clear();
            double[,] f2 = new double[(int)numericUpDown1.Value+1, (int)numericUpDown2.Value+1];
            double[,] f3 = new double[(int)numericUpDown2.Value+1, (int)numericUpDown3.Value+1];
            wij.Add(f2);
            wij.Add(f3);

            for (int i = 0; i < wij.Count; i++)
                for (int j = 0; j < wij[i].GetLength(0); j++)
                    for (int h = 0; h < wij[i].GetLength(1); h++)
                        wij[i][j,h] = f.NextDouble();

            double[] fy1 = new double[(int)numericUpDown2.Value+1];
            double[] fy2 = new double[(int)numericUpDown3.Value+1];

            y.Clear();

            y.Add(fy1);
            y.Add(fy2);

            y[0][0] = 1;
            y[1][0] = 1;

            delta.Clear();

            double[] fdelta1 = new double[(int)numericUpDown2.Value+1];
            double[] fdelta2 = new double[(int)numericUpDown3.Value+1];

            delta.Add(fdelta1);
            delta.Add(fdelta2);
        }
        void Заполнение_таблицы()
        {
            dataGridView1.Rows.Clear();
            dataGridView1.Columns.Clear();
            for (int i = 0; i < numericUpDown1.Value; i++)
            {
                DataGridViewTextBoxColumn g1 = new DataGridViewTextBoxColumn();
                g1.HeaderText = "X" + (i + 1).ToString();
                g1.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                dataGridView1.Columns.Add(g1);
            }
            for (int i = 0; i < numericUpDown3.Value; i++)
            {
                DataGridViewTextBoxColumn g2 = new DataGridViewTextBoxColumn();
                g2.HeaderText = "Y" + (i + 1).ToString();
                g2.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                dataGridView1.Columns.Add(g2);
            }
            for (int i = 0; i < numericUpDown3.Value; i++)
            {
                DataGridViewTextBoxColumn g3 = new DataGridViewTextBoxColumn();
                g3.HeaderText = "Yitog";
                g3.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                dataGridView1.Columns.Add(g3);
            }
        }
        double Вычисление_двуслойного(int layer, int number, int iter)
        {
            double S=0;
            if (layer == 0)
            {
                for (int j = 0; j < wij[layer].GetLength(0); j++)
                {
                    if (j == 0)
                        S += wij[layer][j, number];
                    else S += wij[layer][j, number] * Convert.ToDouble(dataGridView1[j-1, iter].Value);
                }
            }
            else if (layer > 0)
            {
                for (int j = 0; j < wij[layer].GetLength(0); j++)
                {
                    S += wij[layer][j, number] * y[layer-1][j];
                }
            }
            //for (int i=)
            return S;
        }
        private void button5_Click(object sender, EventArgs e)
        {
            textBox2.Text = "0";
            for (int i = 0; i < 100; i++)
            {
                Error.Text = Шаг().ToString();
                Error.Refresh();
                textBox2.Text = (Convert.ToInt32(textBox2.Text)+1).ToString();
            }
        }
        double Шаг()
        {
            double максимальная_ошибка = 0;
            for (int iter = 0; iter < dataGridView1.RowCount-1; iter++)
            {
                for (int i = 0; i < wij.Count; i++)
                    for (int j = 1; j < wij[i].GetLength(1); j++)
                    {
                        y[i][j] = Math.Round(1/(1+Math.Exp(-Вычисление_двуслойного(i, j, iter))),3);
                        if (i == wij.Count - 1)
                        {
                            dataGridView1[(int)numericUpDown1.Value + (int)numericUpDown3.Value + j-1, iter].Value = y[i][j];
                            dataGridView1.Refresh();
                        }
                    }

                for (int i = wij.Count - 1; i >= 0; i--)
                    for (int j = 1; j < wij[i].GetLength(1); j++)
                    {
                        Корректировка_синаптических_весов(i, j, iter);
                    }
            }
             for (int i=0; i<dataGridView1.RowCount-1;i++)
                    for (int j=0;j<(int)numericUpDown3.Value;j++)
                        максимальная_ошибка+=Math.Pow(Convert.ToDouble(dataGridView1[i,(int)numericUpDown1.Value+j].Value)-Convert.ToDouble(dataGridView1[i,(int)numericUpDown1.Value+(int)numericUpDown3.Value+j].Value),2);
             максимальная_ошибка = 1 / dataGridView1.RowCount * максимальная_ошибка;
            return максимальная_ошибка;
        }
        private void button6_Click(object sender, EventArgs e)
        {
            Шаг();
        }
        void Корректировка_синаптических_весов(int layer, int numNeirona, int iter)
        {
            if (layer == wij.Count - 1)
            {
                double dw = (Convert.ToDouble(dataGridView1[dataGridView1.Columns.Count - Convert.ToInt32(numericUpDown3.Value) + numNeirona-2, iter].Value) - y[layer][numNeirona]) * y[layer][numNeirona] * (1 - y[layer][numNeirona]);
                delta[layer][numNeirona] = dw;
                for (int i = 1; i < wij[layer].GetLength(0); i++)
                {
                    wij[layer][i, numNeirona] = wij[layer][i, numNeirona] + dw * y[layer - 1][i]*(int)numericUpDown4.Value;
                }
            }
            else
            {
                double dw = y[layer][numNeirona] * (1 - y[layer][numNeirona]);
                double sumdw = 0;
                for (int j = 1; j < wij[layer + 1].GetLength(1); j++)
                    sumdw += delta[layer + 1][j] * wij[layer + 1][numNeirona, j];
                dw *= sumdw;
                for (int i = 1; i < wij[layer].GetLength(0); i++)
                {
                    if (layer != 0)
                        wij[layer][i, numNeirona] = wij[layer][i, numNeirona] + dw * y[layer - 1][i] * (int)numericUpDown4.Value;
                    else wij[layer][i, numNeirona] = wij[layer][i, numNeirona] + dw * Convert.ToDouble(dataGridView1[i - 1, iter].Value) * (int)numericUpDown4.Value;
                }
                //здесь возможна проверка на нуль dw
                delta[layer][numNeirona] = dw;
            }
        }

        #endregion

        #region многослойноый_персептрон

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked == true)
                textBox3.Enabled = true;
            else textBox3.Enabled = false;
        }
        private void button8_Click(object sender, EventArgs e)
        {
            button10.Enabled = true;
            button9.Enabled = true;
            Заполнение_таблицы_многослойного();
            Начальные_параметры_многослойного();
        }
        void Заполнение_таблицы_многослойного()
        {
            dataGridView2.Rows.Clear();
            dataGridView2.Columns.Clear();
            for (int i = 0; i < numericUpDown6.Value; i++)
            {
                DataGridViewTextBoxColumn g1 = new DataGridViewTextBoxColumn();
                g1.HeaderText = "X" + (i + 1).ToString();
                g1.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                dataGridView2.Columns.Add(g1);
            }
            for (int i = 0; i < numericUpDown7.Value; i++)
            {
                DataGridViewTextBoxColumn g2 = new DataGridViewTextBoxColumn();
                g2.HeaderText = "Y" + (i + 1).ToString();
                g2.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                dataGridView2.Columns.Add(g2);
            }
            for (int i = 0; i < numericUpDown7.Value; i++)
            {
                DataGridViewTextBoxColumn g3 = new DataGridViewTextBoxColumn();
                g3.HeaderText = "Yitog";
                g3.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                dataGridView2.Columns.Add(g3);
            }
        }
        void Начальные_параметры_многослойного()
        {
            //Создаем матрицу синаптических связей
            wij.Clear();
            double[,] f2;
            double[,] f3;
            if (!checkBox1.Checked)
            {
                f2 = new double[(int)numericUpDown6.Value + 1, (int)numericUpDown8.Value + 1];
                wij.Add(f2);
                for (int i = 1; i < (int)numericUpDown5.Value; i++)
                {
                    f2 = new double[(int)numericUpDown8.Value + 1, (int)numericUpDown8.Value + 1];
                    wij.Add(f2);
                }
                f3 = new double[(int)numericUpDown8.Value + 1, (int)numericUpDown7.Value + 1];
            }
            else
            {
                f2 = new double[(int)numericUpDown6.Value + 1, Convert.ToInt32(textBox3.Text.Split(',')[0]) + 1];
                wij.Add(f2);
                for (int i = 1; i < textBox3.Text.Split(',').Length; i++)
                {
                    f2 = new double[Convert.ToInt32(textBox3.Text.Split(',')[i - 1]) + 1, Convert.ToInt32(textBox3.Text.Split(',')[i]) + 1];
                    wij.Add(f2);
                }
                f3 = new double[Convert.ToInt32(textBox3.Text.Split(',')[textBox3.Text.Split(',').Length - 1]) + 1, (int)numericUpDown7.Value + 1];
            }
            //Заполняем матрицу синаптических связей случайными числами от 0 до 1
            wij.Add(f3);

            for (int i = 0; i < wij.Count; i++)
                for (int j = 0; j < wij[i].GetLength(0); j++)
                    for (int h = 0; h < wij[i].GetLength(1); h++)
                        wij[i][j, h] = f.NextDouble();

            //Создаем матрицы выходных данных на каждом слое и матрицы ошибок
            y.Clear();
            delta.Clear();
            if (!checkBox1.Checked)
            {
                for (int i = 0; i < numericUpDown5.Value; i++)
                {
                    double[] fy1 = new double[(int)numericUpDown8.Value + 1];
                    y.Add(fy1);
                    double[] fdelta1 = new double[(int)numericUpDown8.Value + 1];
                    delta.Add(fdelta1);
                }
            }
            else
            {
                for (int i = 0; i < textBox3.Text.Split(',').Length; i++)
                {
                    double[] fy1 = new double[Convert.ToInt32(textBox3.Text.Split(',')[i]) + 1];
                    y.Add(fy1);
                    double[] fdelta1 = new double[Convert.ToInt32(textBox3.Text.Split(',')[i]) + 1];
                    delta.Add(fdelta1);
                }
            }
            double[] fy2 = new double[(int)numericUpDown7.Value + 1];

            y.Add(fy2);

            y[0][0] = 1;
            y[1][0] = 1;

            double[] fdelta2 = new double[(int)numericUpDown7.Value + 1];

            delta.Add(fdelta2);
        }
        private void numericUpDown6_ValueChanged(object sender, EventArgs e)
        {
            button10.Enabled = false;
            button9.Enabled = false;
            Оптимальное_число_нейронов_на_скрытом_слое();
        }
        private void button10_Click(object sender, EventArgs e)
        {
            textBox4.Text = "1";
            textBox2.Text = "0";
            button10.Enabled = false;
            button9.Enabled = false;
            button11.Enabled = true;
            Thread t = new Thread(Поехали);
            t.Start();
        }
        void Поехали()
        {
            while (Ошибка > 0.001 && !Пауза)
            {
                Ошибка = Math.Round(Шаг_Многослойного(), 10);
                textBox4.Invoke(new Action(() => { textBox4.Text = Ошибка.ToString(); }));
                textBox4.Invoke(new Action(() => { textBox4.Refresh(); }));
                textBox5.Invoke(new Action(() => { textBox5.Text = (Convert.ToInt32(textBox5.Text) + 1).ToString(); }));
                textBox5.Invoke(new Action(() => { textBox5.Refresh(); }));
            }
            if (!Пауза)
            {
                button10.Invoke(new Action(() => { button10.Enabled = true; }));
                button9.Invoke(new Action(() => { button9.Enabled = true; }));
                button11.Invoke(new Action(() => { button11.Enabled = false; }));
            }
        }
        double Шаг_Многослойного()
        {
            double максимальная_ошибка = 0;
            for (int iter = 0; iter < dataGridView2.RowCount - 1; iter++)
            {
                for (int i = 0; i < wij.Count; i++)
                    for (int j = 1; j < wij[i].GetLength(1); j++)
                    {
                       // if (i != wij.Count - 1)
                            y[i][j] = Math.Round(1 / (1 + Math.Exp(-Вычисление_многослойного(i, j, iter))), 3);
                        //y[i][j] = Вычисление_многослойного(i, j, iter) * Convert.ToDouble(textBox6.Text);
                        if (i == wij.Count - 1)
                        {
                            dataGridView2.Invoke(new Action(()=> {dataGridView2[(int)numericUpDown6.Value + (int)numericUpDown7.Value + j - 1, iter].Value = y[i][j];}));
                            dataGridView2.Invoke(new Action(() => { dataGridView2.Refresh(); }));
                        }
                    }

                for (int i = wij.Count - 1; i >= 0; i--)
                    for (int j = 1; j < wij[i].GetLength(1); j++)
                    {
                        Корректировка_синаптических_весов_многослойного(i, j, iter);
                    }
            }
            for (int i = 0; i < dataGridView2.RowCount - 1; i++)
                for (int j = 0; j < (int)numericUpDown7.Value; j++)
                    максимальная_ошибка += Math.Pow(Convert.ToDouble(dataGridView2[(int)numericUpDown6.Value + j,i].Value) - Convert.ToDouble(dataGridView2[(int)numericUpDown6.Value + (int)numericUpDown7.Value + j,i].Value), 2);
            максимальная_ошибка = (double)1 / dataGridView2.RowCount * максимальная_ошибка;
            return максимальная_ошибка;
        }
        double Вычисление_многослойного(int layer, int number, int iter)
        {
            double S = 0;
            if (layer == 0)
            {
                for (int j = 0; j < wij[layer].GetLength(0); j++)
                {
                    if (j == 0)
                        S += wij[layer][j, number];
                    else S += wij[layer][j, number] * Convert.ToDouble(dataGridView2[j - 1, iter].Value);
                }
            }
            else if (layer > 0)
            {
                for (int j = 0; j < wij[layer].GetLength(0); j++)
                {
                    S += wij[layer][j, number] * y[layer - 1][j];
                }
            }
            //for (int i=)
            return S;
        }
        private void button9_Click(object sender, EventArgs e)
        {
            textBox4.Text = Шаг_Многослойного().ToString();
            textBox4.Refresh();
            textBox5.Text = (Convert.ToInt32(textBox5.Text) + 1).ToString();
            textBox5.Refresh();
        }
        void Корректировка_синаптических_весов_многослойного(int layer, int numNeirona, int iter)
        {
            if (layer == wij.Count - 1)
            {
                double dw = (Convert.ToDouble(dataGridView2[Convert.ToInt32(numericUpDown6.Value) + numNeirona-1, iter].Value) - y[layer][numNeirona]) * y[layer][numNeirona] * (1 - y[layer][numNeirona]);
                delta[layer][numNeirona] = dw;
                for (int i = 1; i < wij[layer].GetLength(0); i++)
                {
                    wij[layer][i, numNeirona] = wij[layer][i, numNeirona] + dw * y[layer - 1][i] * Convert.ToDouble(textBox6.Text);
                }
            }
            else
            {
                double dw = y[layer][numNeirona] * (1 - y[layer][numNeirona]);
                double sumdw = 0;
                for (int j = 1; j < wij[layer + 1].GetLength(1); j++)
                    sumdw += delta[layer + 1][j] * wij[layer + 1][numNeirona, j];
                dw *= sumdw;
                for (int i = 1; i < wij[layer].GetLength(0); i++)
                {
                    if (layer != 0)
                        wij[layer][i, numNeirona] = wij[layer][i, numNeirona] + dw * y[layer - 1][i] * Convert.ToDouble(textBox6.Text);
                    else wij[layer][i, numNeirona] = wij[layer][i, numNeirona] + dw * Convert.ToDouble(dataGridView2[i - 1, iter].Value) * Convert.ToDouble(textBox6.Text);
                }
                //здесь возможна проверка на нуль dw
                delta[layer][numNeirona] = dw;
            }
        }
        private void textBox3_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!((int)e.KeyChar == 44 || (int)e.KeyChar == 46 || (int)e.KeyChar >= 48 && (int)e.KeyChar <= 57 || (int)e.KeyChar == 8))
                e.Handled = true;
            if ((int)e.KeyChar == 44 && textBox3.Text.Split(',').Length == numericUpDown5.Value)
            {
                e.Handled = true;
                MessageBox.Show("Вы уже ввели данные для всех слоев. Если требуется, то увеличте количество прмежуточных слоев и продолжите заполнение", "Предупреждение!");
            }
        }
        private void button11_Click(object sender, EventArgs e)
        {
            if (((Button)sender).Text == "Пауза")
            {
                ((Button)sender).Text = "Продолжить";
                Пауза = true;
            }
            else if (((Button)sender).Text == "Продолжить")
            {
                ((Button)sender).Text = "Пауза";
                Пауза = false;
                Thread t = new Thread(Поехали);
                t.Start();
            }
        }
        void Оптимальное_число_нейронов_на_скрытом_слое()
        {
            int Ny = (int)numericUpDown7.Value;
            int Nx = (int)numericUpDown6.Value;
            int Q = dataGridView2.Rows.Count - 1;
            from.Text = ((Ny * Q) / ((1 + Math.Log(Q, 2)) * (Nx + Ny))).ToString();
            to.Text = (Ny * (Q / Nx + 1) * (Nx + Ny + 1) / (Nx + Ny) + Ny / (Nx + Ny)).ToString();
        }

        #endregion

        private void dataGridView2_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            Оптимальное_число_нейронов_на_скрытом_слое();
        }
    }
}
